package gao.xiaolei.bluetoothcontroller;

import android.Manifest;
import android.app.Activity;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import java.util.HashMap;
import java.util.Map;
import gao.xiaolei.bluetoothcontroller.blue.BlueToothController;
import gao.xiaolei.bluetoothcontroller.blue.callback.ConnectCallback;
import gao.xiaolei.bluetoothcontroller.blue.callback.OnReceiverCallback;
import gao.xiaolei.bluetoothcontroller.blue.callback.OnWriteCallback;
import gao.xiaolei.bluetoothcontroller.blue.callback.ScanCallback;
import gao.xiaolei.bluetoothcontroller.blue.util.HexUtil;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.EventChannel;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry.Registrar;

/** BluetoothcontrollerPlugin */
public class BluetoothcontrollerPlugin implements FlutterPlugin, MethodCallHandler, ActivityAware {
  private static final String CHANNEL_METHOD = "my.flutter.io/bluetooth";
  private static final String EVENT_CHANNEL = "my.flutter.event/bluetooth";
  private Map<String,BlueToothController> blueControllerMap=new HashMap<>();//用map来储存蓝牙Controller对象,减少代码的冗余
  private EventChannel.EventSink mySink;//flutter中订阅了要接收我发出的消息的观察者们
  private Handler mHandler = new Handler(Looper.getMainLooper());//handle的作用是为了在主线程中向flutter返回消息,Flutter1.7.8版本添加了线程安全，需要原生在主线程中返回给Flutter
  private Context context;
  private Activity activity;
  /// The MethodChannel that will the communication between Flutter and native Android
  ///
  /// This local reference serves to register the plugin with the Flutter Engine and unregister it
  /// when the Flutter Engine is detached from the Activity
  private MethodChannel channel;

  @Override
  public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
    channel = new MethodChannel(flutterPluginBinding.getFlutterEngine().getDartExecutor(), CHANNEL_METHOD);
    channel.setMethodCallHandler(this);
    context=flutterPluginBinding.getApplicationContext();
    new EventChannel(flutterPluginBinding.getBinaryMessenger(), EVENT_CHANNEL).setStreamHandler(new EventChannel.StreamHandler() {//创建对flutter的消息发送channel
      @Override
      public void onListen(Object o, EventChannel.EventSink eventSink) {//当flutter中有人要订阅我们发送的消息时就会调用这个函数
        mySink=eventSink;//将观察者加入list中
      }
      @Override
      public void onCancel(Object o) {//当flutter中有人要取消订阅我们发送的消息时就会调用这个函数
        mySink=null;//将观察者移除
      }
    });
  }

  // This static function is optional and equivalent to onAttachedToEngine. It supports the old
  // pre-Flutter-1.12 Android projects. You are encouraged to continue supporting
  // plugin registration via this function while apps migrate to use the new Android APIs
  // post-flutter-1.12 via https://flutter.dev/go/android-project-migration.
  //
  // It is encouraged to share logic between onAttachedToEngine and registerWith to keep
  // them functionally equivalent. Only one of onAttachedToEngine or registerWith will be called
  // depending on the user's project. onAttachedToEngine or registerWith must both be defined
  // in the same class.
  public static void registerWith(Registrar registrar) {

  }
  private ScanCallback scanCallback=new ScanCallback() {
    @Override
    public void onSuccess(BlueToothController controller) {
      if(!controller.isScannedTarget()) {//如果扫描结束了还没有扫描到目标设备就肯定连接不上了
        System.out.println("扫描不到目标设备！");
        String deviceName=controller.getDeviceName();//获取该controller的deviceName
        blueControllerMap.remove(controller);//将controller从map中移除
        sendFailMsgToEventChannel("90001", "扫描不到目标设备", deviceName);//向flutter发送消息
      }
    }

    @Override
    public void onScanning(BluetoothDevice device) {
      System.out.println("扫描到一个！");
    }
  };

  private ConnectCallback connectCallback=new ConnectCallback() {
    @Override
    public void onConnSuccess(BlueToothController controller) {
      System.out.println("连接成功！");
      String deviceName=controller.getDeviceName();
      Map<String,Object> successData=new HashMap<>(2);
      successData.put("code","80001");
      successData.put("deviceName",deviceName);
      sendSuccessMsgToEventChannel(successData);//向flutter发送连接成功的消息
    }

    @Override
    public void onConnFailed(BlueToothController controller) {
      if(controller.isInitiativeToDisconnect()){//如果是自己手动断开连接的话
        System.out.println("连接被手动断开");
        Map<String,Object> successData=new HashMap<>(2);
        successData.put("deviceName",controller.getDeviceName());
        successData.put("code","80002");
        blueControllerMap.remove(controller);//将controller从map中移除
        sendSuccessMsgToEventChannel(successData);
      }else{//如果是被动断开的话
        System.out.println("连接自己断开");
        blueControllerMap.remove(controller);//将controller从map中移除
        sendFailMsgToEventChannel("90002","与设备的连接断开",controller.getDeviceName());
      }
    }
  };

  private OnWriteCallback onWriteCallback=new OnWriteCallback() {
    @Override
    public void onSuccess(String characteristicUuid) {
      System.out.println("特征值：".concat(characteristicUuid).concat("写入成功！"));
    }

    @Override
    public void onFailed(String characteristicUuid, int state) {
      System.out.println("特征值：".concat(characteristicUuid).concat("写入失败！").concat("state:").concat(String.valueOf(state)));
    }
  };
  private OnReceiverCallback receiverCallback= (controller, characteristicUuid, value) -> {
    System.out.println("notify特征值：".concat(characteristicUuid).concat("传来数据：").concat(HexUtil.bytesToHexString(value)));
    Map<String,Object> notifyData=new HashMap<>(4);
    String deviceName=controller.getDeviceName();
    notifyData.put("code","80005");
    notifyData.put("deviceName",deviceName);
    notifyData.put("notifyUuid",characteristicUuid);
    notifyData.put("data",value);
    sendSuccessMsgToEventChannel(notifyData);//向flutter发送notify传回来的消息
  };
  @Override
  public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
    switch (call.method){
      case "connectDevice"://如果是要去连接蓝牙设备的话
        System.out.println("去连接设备啦");
        Map<String,Object> connectDataMap=call.arguments();
        BlueToothController controller= BlueToothController.getInstance(
                (int)connectDataMap.get("uuidDataType"),
                (String)connectDataMap.get("deviceUuid"),
                (String)connectDataMap.get("notify_d"),
                (String)connectDataMap.get("notifyUuid"),
                context);
        controller.setDeviceName((String)connectDataMap.get("deviceName"));
        controller.setScanCallback(scanCallback);
        controller.setConnectCallback(connectCallback);
        controller.setReceiverCallback(receiverCallback);
        controller.setWriterCallback(onWriteCallback);
        blueControllerMap.put(controller.getDeviceName(),controller);
        controller.connectDriver();//连接设备
        result.success("80003");//跟flutter报告说开始去连接设备了
        break;
      case "applyBlueAuth"://如果是要去申请设备权限的话
        local();
        result.success("80004");//跟flutter报告说开始去连接设备了
        break;
      case "sendData"://如果是向设备发送数据的话
        Map<String,Object> sendDataMap=call.arguments();
        BlueToothController targetController=blueControllerMap.get((String)sendDataMap.get("deviceName"));
        targetController.sendData(
                (String)sendDataMap.get("serviceUuid"),
                (String)sendDataMap.get("writeUuid"),
                (String)sendDataMap.get("notifyUuid"),
                (byte[]) sendDataMap.get("data"),
                (boolean) sendDataMap.get("isWithResult"));
        break;
      case "disConnectDevice"://如果是手动断开连接
        System.out.println("要去断开连接啦");
        BlueToothController disConnectController=blueControllerMap.get((String)call.arguments());
        disConnectController.disConnectDriver();
        break;
      default://如果没有此方法
        result.notImplemented();
        break;
    }
  }

  @Override
  public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
    channel.setMethodCallHandler(null);
  }

  //向观察者们轮询发送成功消息
  private void sendSuccessMsgToEventChannel(Object msg){
    if(mySink!=null)
      runOnMainThread(()->{
        mySink.success(msg);
      });
  }

  //向观察者们轮询发送失败消息
  private void sendFailMsgToEventChannel(String errCode, String errMsg, Object errDetail){
    if(mySink!=null)
      runOnMainThread(()->{
        mySink.error(errCode,errMsg,errDetail);
      });
  }

  /**
   * 判断是否具有权限
   */
  private void local() {
    if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
      Log.i("dd", "sdk < 28 Q");
      if (ActivityCompat.checkSelfPermission(context,
              Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
              || ActivityCompat.checkSelfPermission(context,
              Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
        String[] strings =
                {Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION};
        ActivityCompat.requestPermissions(activity, strings, 1);
      }
    } else {
      if (ActivityCompat.checkSelfPermission(context,
              Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
              || ActivityCompat.checkSelfPermission(context,
              Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
              || ActivityCompat.checkSelfPermission(context,
              "android.permission.ACCESS_BACKGROUND_LOCATION") != PackageManager.PERMISSION_GRANTED) {
        String[] strings = {android.Manifest.permission.ACCESS_FINE_LOCATION,
                android.Manifest.permission.ACCESS_COARSE_LOCATION,
                "android.permission.ACCESS_BACKGROUND_LOCATION"};
        ActivityCompat.requestPermissions(activity, strings, 2);
      }
    }
  }

  /**
   * 判断当前线程是否是主线程
   *
   */
  private boolean isMainThread() {
    return Looper.myLooper() == Looper.getMainLooper();
  }

  /**
   * 将目标代码快运行在主线程中
   *
   */
  private void runOnMainThread(Runnable runnable) {
    if (isMainThread()) {
      runnable.run();
    } else {
      if (mHandler != null) {
        mHandler.post(runnable);
      }
    }
  }

  @Override
  public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {
    this.activity=binding.getActivity();
  }

  @Override
  public void onDetachedFromActivityForConfigChanges() {

  }

  @Override
  public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) {

  }

  @Override
  public void onDetachedFromActivity() {

  }
}
